import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:dio/io.dart';
import 'package:encrypt/encrypt.dart';
import 'package:pointycastle/asymmetric/api.dart';
import 'package:flutter/services.dart';
import 'package:example/base/http_resp_exception.dart';
import 'package:example/utils/common.dart';

import '../utils/local_manage.dart';
import 'const_config.dart';


///系统环境
enum SysEnvironmentEnum {
  debug,      // 开发环境
  test,       // 测试环境
  uat,        // 预发布环境
  release,    // 线上环境
}

///api类型
enum ApiTypeEnum {
  normal,        // 正常使用的api
  common,       // 公共接口
}

class HttpConfig {

  static final HttpConfig _singleton = HttpConfig._internal();

  factory HttpConfig() {
    return _singleton;
  }

  HttpConfig._internal();

  static late BaseOptions options;

  static late Dio dio;

  //显示错误提示
  static bool isToast = true;

  ///===================================
  ///环境配置 更改这个参数 就可以跟换开发环境
  ///===================================
  static const SysEnvironmentEnum sysEnvironment = SysEnvironmentEnum.release;

  static String baseUrl = getBaseUrl();
  static String commonBaseUrl = getBaseUrl(a:  ApiTypeEnum.common);

  static String getBaseUrl({
    SysEnvironmentEnum? e = sysEnvironment ,
    ApiTypeEnum? a = ApiTypeEnum.normal}) {

    String baseUrl = '';

    if(e == SysEnvironmentEnum.debug){
      baseUrl = '';

    }else if(e == SysEnvironmentEnum.test){
      baseUrl = '';
    }else if(e == SysEnvironmentEnum.uat){
      baseUrl = '';
    }else if(e == SysEnvironmentEnum.release){
      baseUrl = '';
    }

    return baseUrl;
  }

  //初始化
  static void init() {
    dio = _initDio(baseUrl);
  }

  static _initDio(String baseUrl) {
    options = BaseOptions();
    options.baseUrl = baseUrl;
    options.connectTimeout =  const Duration(seconds: 20);
    options.receiveTimeout = const Duration(seconds: 20);
    Dio dio = Dio(options);

    // //解决ios无法抓包的问题
    if (Platform.isAndroid) {
      // setAndroidProxy();
    } else {
      getProxyIOS();
    }
    dio.interceptors.add(InterceptorsWrapper(
      onRequest: (RequestOptions options, RequestInterceptorHandler handler) {

        String? token = getToken();

        if (isNotEmptyOrNull(token)) {
          options.headers["Authorization"] = 'Bearer $token';
        }

        DateTime dateTime = DateTime.now();
        options.headers["timestamp"] = dateTime.millisecondsSinceEpoch;

        options.headers["User-Agent"] = Platform.operatingSystem;

        var requestJson = options.data;
        if(options.path.contains('user/tenant/auth') == false){
          loggerJson.d("请求参数：\nurl：${options.uri.toString()}\nheaders："
              "${jsonEncode(options.headers)}"
              "\nmethod:${options.method.toString()}\n"
              "params:$requestJson");
        }
        // encryption(requestJson).then((value){
        //      options.data=value;
        //      handler.next(options);
        // });
        handler.next(options);
      },
      onResponse: (Response response, ResponseInterceptorHandler handler) {
        loggerJson.d("请求结果：\nurl:${response.realUri}\n${jsonEncode(response.data)}");
        int code = response.data?["code"];
        dynamic data = response.data?["data"];
        bool isNull = data == "";
        bool isNullList = data is List && data.isEmpty;
        if (code != 200 && (isNull || isNullList)) {
          // 防止go code非200 data为空字符串或空数组
          response.data?["data"] = null;
        }
        handler.next(response);

        //用户被顶掉-重新登陆
        if (code == 401) {
          logout();
        }

      },
      onError: (
          DioException e,
        ErrorInterceptorHandler handler,
      ) {
        HttpRespException appException = HttpRespException.init(e);
        // logger.e('请求失败: ${appException.toString()}');
        // showToast(appException.message);
        // e.error = appException;
        handler.next(e);
        //用户被顶掉-重新登陆
        if (appException.code == 401) {
          logout();
        }else {
          showToast('网络错误，code=${appException.code}');
        }
      },
    ));
    return dio;
  }

  ///  加密
  static Future encryption(content) async {
    final parser = RSAKeyParser();
    String publicKeyString =
        await rootBundle.loadString('assets/rsa_key/rsa_public_key.pem');
    RSAPublicKey publicKey = parser.parse(publicKeyString) as RSAPublicKey;
    final encrypter = Encrypter(RSA(publicKey: publicKey));
    return encrypter.encrypt(content).base64;
  }

  static isEnableProxy() {
    return (HttpConfig.dio.httpClientAdapter as IOHttpClientAdapter)
            .createHttpClient !=
        null;
  }

  static setDefaultProxy() {
    if(HttpConfig.sysEnvironment == SysEnvironmentEnum.uat ||
        HttpConfig.sysEnvironment == SysEnvironmentEnum.release){
      return;
    }
    bool openStaty = LocalManage.getSp().getBool(ConstConfig.proxyStaty) ?? false;
    if(openStaty == false){
      return;
    }
    String? ipStr = LocalManage.getSp().getString(ConstConfig.proxyIP);
    String? hostStr = LocalManage.getSp().getString(ConstConfig.proxyHost);
    HttpConfig.setProxy(ipStr, hostStr);
  }

  static cleanProxy() {
    HttpConfig.dio.httpClientAdapter = IOHttpClientAdapter();
  }

  static setProxy(String? ip, String? host) {
    HttpConfig.dio.httpClientAdapter = IOHttpClientAdapter();
    if (isNotEmptyOrNull(ip) && isNotEmptyOrNull(host)) {
      (HttpConfig.dio.httpClientAdapter as IOHttpClientAdapter).createHttpClient = (){
        var httpClient = HttpClient();
        httpClient.userAgent = null;
        httpClient.badCertificateCallback =
            (X509Certificate cert, String host, int port) {
          return Platform.isAndroid;
        };
        httpClient.findProxy = (uri) {
          return "PROXY $ip:$host";
        };
        return httpClient;
      };
    }
  }

  static getProxyIOS() async {
    MethodChannel platform = const MethodChannel("com.wochengmetals.wisdomlogistics.channel");
    final result = await platform.invokeMethod("getProxyIOS");
    String? resultStr = result as String;
    if (resultStr.isNotEmpty) {
      (dio.httpClientAdapter as IOHttpClientAdapter).createHttpClient =
          () {
        var httpClient = HttpClient();
        httpClient.findProxy = (uri) {
          return 'PROXY $resultStr:8888';
        };
        return httpClient;
      };
    }
  }

  static setAndroidProxy() async {
    MethodChannel channel = const MethodChannel('com.zsts.http.proxy');
    Future<String?> getHost = channel.invokeMethod('getProxyHost');
    Future<String?> getPort = channel.invokeMethod('getProxyPort');
    var result = await Future.wait([getHost, getPort]);
    if (result.length == 2 &&
        result[0] != null &&
        result[0]!.isNotEmpty &&
        result[1] != null &&
        result[1]!.isNotEmpty) {
      String host = result[0].toString();
      String port = result[1].toString();
      (dio.httpClientAdapter as IOHttpClientAdapter).createHttpClient =
          () {
          var httpClient = HttpClient();
          httpClient.findProxy = (uri) {
            return 'PROXY $host:$port';
          };
          return httpClient;
      };
    }
  }

  getBaseUrlStr(){
    return baseUrl;
  }
  getCommonBaseUrlStr(){
    return commonBaseUrl;
  }

}

